#include "storage_api.h"
#include "record_set.h"
#include "rec_data_io.h"
#include "cross_com.h"
#include "file_manager_arr.h"
#include <map>
#include <vector>
#include "rec_rw_factroy.h"
#include "fifo_lhn_frame.h"
#include "replay_manager.h"
#include "rec_switch_rule.h"

using namespace std;

CRecordSet                 *g_pRecSet   = NULL;
StorageConfig				g_storageCfg;
//录像列表
CCross_Lock                 g_lock;
CRecordDataIO				g_rec_dataIO;
//回放缓冲队列
#ifdef _SPT_BACKUP_
CRecBackup                  g_rec_backup;
#endif // _SPT_BACKUP_
REC_FILE_LIST               g_fileLst;
map<int, MAP_CH_FILE_T> 	g_mpClientFile;    //录像列表
CFile_manager_arr          g_pFileMangerArr;

CLHNFrame *				   g_pFrmBufArr = NULL;//缓冲

STORAGE_STATUS_CBAK        g_status_bak = NULL;
CReplayManager *            g_replayer;
CReplayCtrl    *            g_replayCtrl;
CClientManager *			g_clientManger;
CRecSwitchRule *            g_pRecSwitch = NULL;
#ifdef _SIMULATE_RECORD_
#include "MultiCHData.h"

#endif
int STORAGE_INIT(StorageConfig storageCfg)
{
	int ret= 0;
	int ch = 0;
	RECORD_DIR_INFO_S recDirInfo;


	int bufSize = SIZE_1MB;
	uint32_t oneFrmSize = SIZE_KB(128);
	int recChNum = 0;
	int chNum = g_storageCfg.channelNum = storageCfg.channelNum;
	g_storageCfg.cache_chNum            = storageCfg.channelNum;
	g_storageCfg.bPrepare               = storageCfg.bPrepare;
    g_storageCfg.nPerpareSecs           = storageCfg.nPerpareSecs;
    g_storageCfg.bCycleRec              = storageCfg.bCycleRec;

	if( storageCfg.sptClientNum >= 1)
	{
		g_storageCfg.sptClientNum    = storageCfg.sptClientNum;
	}
	else
	{
		g_storageCfg.sptClientNum    = 5;
	}

	g_storageCfg.ioContinue_tm   = storageCfg.ioContinue_tm;
	g_storageCfg.record_size     = storageCfg.record_size;

	strcpy(g_storageCfg.dev,storageCfg.dev);

	memcpy(g_storageCfg.chInfo,storageCfg.chInfo,sizeof(CH_INFO)*MAX_CH_NUM);

	if(storageCfg.bMixAudio)
	{   //取消混合音频
		CRecReadBase::MIX_AUDIO = true;
	}

	CRecSwitchRule * pRecSwitch = CRecSwitchRule::GetInstance();
	if( SWITCH_BY_TIME == storageCfg.pkt_mode)
	{
		pRecSwitch->SetSwitchParm(storageCfg.pkt_mode,storageCfg.pkt_secs);
	}
	else
	{
		pRecSwitch->SetSwitchParm(storageCfg.pkt_mode,SIZE_MB(storageCfg.pkt_sz_MB));
	}

	strcpy(recDirInfo.df_mntPath,storageCfg.df_mntPath);
	strcpy(recDirInfo.norDir,storageCfg.norDir);
	strcpy(recDirInfo.evtDir,storageCfg.evtDir);
	strcpy(recDirInfo.capture,storageCfg.capture);
	strcpy(recDirInfo.thumbnailDir,storageCfg.thumbnailDir);
	strcpy(recDirInfo.separtor, storageCfg.titile_dot);

	if( NULL == g_pFrmBufArr)
	{
		g_pFrmBufArr = new CLHNFrame[chNum];
		for(ch = 0; ch< g_storageCfg.cache_chNum; ch++)
		{
			bufSize    = storageCfg.chInfo[ch].mml_cache_sz;
			oneFrmSize = storageCfg.chInfo[ch].maxFrameSize;

			ret = g_pFrmBufArr[ch].Open(bufSize,oneFrmSize,ch);
			if(ret < 0)
			{
				TRACE_ERR("Open ch %d fail.\n",ch);
			}

			TRACE("CH%02d Storge Init FIFO BUF,size %d oneFrmSize %d  \n",ch,bufSize,oneFrmSize);
		}
	}

	recDirInfo.fbox_fmt = storageCfg.fbox_fmt;
	//挂载目录
	for(ch = 0 ; ch < chNum; ch++)
	{
		if(storageCfg.chInfo[ch].enable)
		{
			recChNum++;
		}
	}

	//初始化文件管理类参数
	g_pFileMangerArr.Init(recChNum);

	ret = g_pFileMangerArr.AddFileManager(storageCfg.dev,recDirInfo);
	if(ret < 0)
	{
		TRACE("Init file manager fail. ret \n",ret);
	}
	g_pFileMangerArr.SetNorSpace(storageCfg.nor_space);  //设置正常录像文件夹配额

    if(0 != g_storageCfg.record_size)
    {
        g_pFileMangerArr.SetRecordSize(g_storageCfg.record_size);
    }


    for(ch = 0 ; ch < chNum; ch++)
	{   //一般默认全部打开的
        g_storageCfg.chInfo[ch].rec_cache_sz = storageCfg.chInfo[ch].rec_cache_sz;
    }
	g_storageCfg.getfrm_sz = storageCfg.getfrm_sz;
	//扫描磁盘设备　
	if(NULL == g_pRecSet)
	{
		g_pRecSet = new CRecordSet(&g_pFileMangerArr,chNum);
	}

	if(NULL == g_clientManger)
	{
		g_clientManger = new CClientManager(chNum,g_storageCfg.sptClientNum);
	}
	//开启录像
	for(ch = 0 ; ch < chNum; ch++)
	{
        //一般默认全部打开的
		if(storageCfg.chInfo[ch].enable)
		{
			g_pRecSet->StartRecord(ch,RECORD_MANUAL);
			TRACE("ch %2d start RECORD_MANUAL  \n" ,ch);
		}
	}

	if(NULL == g_replayer)
	{
		g_replayer = new CReplayManager(chNum);
		g_replayCtrl = g_replayer->GetReplayCtrl();
	}

    //文件切换规则
	g_pRecSwitch = CRecSwitchRule::GetInstance();

	return 0;
}

void STORAGE_SET_STATUS_CBAK(STORAGE_STATUS_CBAK cbak)
{
	g_status_bak = cbak;
}

int  STORAGE_SET_REC_DIR(char * dir,RECORD_DIR_INFO_S  dirInfo)
{
	int ret = 0;

	ret = g_pFileMangerArr.InitSorageDir(dir, dirInfo);

	return ret;
}

int  STORAGE_UNINIT(StorageConfig cfg)
{
	int ret = 0;

	STORAGE_STOP_RECORD();

	delete g_pRecSet;

	return ret;
}

int  PTM_STORAGE_SET_DBGINFO(StorageConfig cfg)
{
	int ch = 0;
	TRACE("Set storage cfg scan_drv_no %d .\n",cfg.scan_drv_no);
	//g_pFileMangerArr.SetScan1stDrvNo(cfg.scan_drv_no);

	for(ch = 0 ; ch < g_storageCfg.channelNum; ch++)
	{   //一般默认全部打开的
		if(cfg.chInfo[ch].enable)
		{
			g_pRecSet->StartRecord(ch,RECORD_MANUAL);
			TRACE("ch %2d start RECORD_MANUAL  \n" ,ch);
		}
		else
		{
			g_pRecSet->StopRecord(ch,RECORD_MANUAL);
		}
	}
	return 0;
}

time_t STORAGE_GET_REC_MAXTIME()
{
	time_t recTm = 0;
	time_t destTm = 0;

	g_pFileMangerArr.GetMaxTime(recTm);

	destTm = (time_t)(recTm/1000);

	return destTm;
}

void STORAGE_SET_REC_SIZE(uint32_t recordSize)
{
	g_pFileMangerArr.SetRecordSize(recordSize);
}

void STORAGE_SET_SWITCH_PARM(int switchMod,int parm)
{
	CRecSwitchRule * pRecSwitch = CRecSwitchRule::GetInstance();

	pRecSwitch->SetSwitchParm(switchMod,parm);

}

void  STORAGE_SET_NOR_SPACE(uint32_t space)
{
	g_pFileMangerArr.SetNorSpace(space);
}

//判断磁盘是否已经初始化
int STORAGE_DISK_IS_INIT(char * dev)
{
// 	bool bRawDev = CSerialFileBase::IsRawDevice(dev);
// 	//通用文件系统
// 	if(bRawDev)
// 	{
// 		CSCSI_Dev* pDev = g_diskInfoSet.GetDevByName(dev);
// 		if(pDev == NULL)
// 		{
// 			TRACE_ERR("No device  %s.\n",dev);
// 			return ERR_NO_DEVICE;
// 		}
// 		CDiskTable diskT;
// 		diskT.Init(pDev);
//
// 		if(	diskT.IsInitSTFS())
// 		{
// 			fprintf(stderr,"Storage disk %s is init.\n",dev);
// 			return true;
// 		}
//
// 		fprintf(stderr,"Storage disk %s not init .\n",dev);
// 	}
// 	else
// 	{
// 		CStorageCommon storageCom;
// 		return storageCom.bInitFileSys(dev);
// 	}
	return false;
}

int  STORAGE_RECORD_FUNC_ISOK()
{

// 	if(  0 == g_diskInfoSet.GetDiskNum())
// 	{
// 		return 1;
// 	}
// 	else
// 	{
// 		if( g_storageCfg.manualRecBIT &&
// 			0 == g_pRecSet->m_recStatusBIT)
// 		{
// 			return 0;//不正常
// 		}
// 	}

	return 1;//正常
}

int STORAGE_START_RECORD()
{
	//开启录像线程
	g_pRecSet->Start();
	//开启录像
	for(int ch = 0 ; ch < g_storageCfg.channelNum; ch++)
	{
		//一般默认全部打开的
		if(g_storageCfg.chInfo[ch].enable)
		{
			g_pRecSet->StartRecord(ch,RECORD_MANUAL);
			TRACE("ch %2d start RECORD_MANUAL  \n" ,ch);
		}

	}

	return 0;
}

int  STOAGE_GET_FREESPACE(uint32_t * pFreeMB, uint32_t* pTotalMB)
{
	if(NULL != pFreeMB)
	{
		*pFreeMB  = g_pFileMangerArr.GetFreeSpaceMB();
	}

	if(NULL != pTotalMB)
	{
		*pTotalMB  = g_pFileMangerArr.GetFreeSpaceMB();
	}

	return 0;
}

 void STORAGE_GET_STORAGE_STAT(StorageStat * pStat)
 {

	 //是否循环录像
	 pStat->CycleRec = (uint8_t)g_pRecSet->IsCyCleRec();

	 //当切换文件分段模式为时间
	 if(SWITCH_BY_TIME == g_pRecSwitch->GetSwitchMod())
	 {
		 pStat->duration = g_pRecSwitch->GetSwitchParmMin();
	 }
	 else
	 {
		 pStat->duration = 0;
	 }

	 //正常紧急录像
	 if(g_pRecSet->GetRecordType(0) == RECORD_IOALARM)
	 {
		 pStat->EvtRecStat = 1;
	 }
	 else
	 {
		  pStat->EvtRecStat = 0;
	 }

	 pStat->resolution   =  0;
	 pStat->audioRecStat =  (uint8_t)g_pRecSet->GetAudioRecEnable(0);

	 if(0 != g_pFileMangerArr.GetDiskNum())
	 {
		 pStat->sdcordStat = 0;
	 }
	 else
	 {
		  pStat->sdcordStat = 1;
	 }
 }

//设置报警录像的时间
int STORAGE_SET_IOALARM(int prepareTm, int ccontinueTm)
{
	 //最大支持预录15S
	if(prepareTm > 15)
	{
		g_storageCfg.nPerpareSecs = 15;
	}
	else
	{
		g_storageCfg.nPerpareSecs = prepareTm;
	}

	//持续录像时间不能够低于5S
	if(ccontinueTm < 5)
	{
		g_storageCfg.ioContinue_tm  = 5;
	}
	else
	{
		g_storageCfg.ioContinue_tm  = ccontinueTm;
	}

	return 0;
}

int START_EVT_RECORD(int ch)
{
	int64_t curTime = 0;
	//停止正常的录像
	g_pRecSet->StopRecord(ch,RECORD_MANUAL,true);
	//切换到紧急录像
	time_t now= 0;
	time(&now);
	curTime = (int64_t)now * STFS_1SEC_MS;

	//从当前时间往前定位,支持预录像功能
	MML_FIFO_SeekTime(curTime,g_storageCfg.nPerpareSecs,ch);

	g_pRecSet->SetAlarmTime(ch,RECORD_IOALARM,g_storageCfg.ioContinue_tm);

	g_pRecSet->StartRecord(ch,RECORD_IOALARM);

	return 0;
}

int STOP_EVT_RECORD(int ch)
{


	g_pRecSet->StopRecord(ch,RECORD_IOALARM,true);

	g_pRecSet->StartRecord(ch,RECORD_MANUAL);

	return 0;
}

int STORAGE_STOP_RECORD()
{
	g_pRecSet->Stop();
	return 0;
}

int STORAGE_CYCLE_REC(int bEnable)
{
	g_pRecSet->SetRecycleRecord((bool)bEnable);
	return 0;
}



int START_RECORD(int ch, FS_RECORD_TYPE recType, int recTmSecs)
{

	if( !g_pRecSet->RecordThreadLive())
	{
		TRACE_ERR("Restart Record thread .\n");
		g_pRecSet->Start();
	}

	if(ch == STFS_ALL_CHANNEL)
	{
		for (int i = 0 ; i < g_pRecSet->GetMaxCHNum(); i++)
		{
			g_pRecSet->StartRecord(i,recType);
			if(recType >= FS_RECORD_MOTION )
			{
				g_pRecSet->SetAlarmTime(i,recType,recTmSecs);
			}
		}
		if( FS_RECORD_MANUAL == recType)
		{
			for(int i = 0; i < g_pRecSet->GetMaxCHNum(); i++)
			{
				g_storageCfg.chInfo[ch].enable = 1;
			}
		}
	}
	else
	{

		if(recType >= FS_RECORD_MOTION)
		{
			g_pRecSet->SetAlarmTime(ch,recType,recTmSecs);
		}

		g_pRecSet->StartRecord(ch,recType);
		if(FS_RECORD_MANUAL  == recType)
		{
			g_storageCfg.chInfo[ch].enable = 1;//  |= ((uint32_t)1<<ch);
		}
	}
	return 0;
}

int STOP_MANUAL_RECORD(int ch)
{
	TRACE_CBS("Stop pauseRecord  CH %02d.\n",ch);

	if(STFS_ALL_CHANNEL == ch)
	{
		CRecordSet::MANUAL_SWITCH &= ~((uint32_t)1<<ch);
		for (int i = 0 ; i < g_pRecSet->GetMaxCHNum(); i++)
		{
			g_pRecSet->StopRecord(i,RECORD_MANUAL,true);
		}
	}
	else
	{
		CRecordSet::MANUAL_SWITCH &= ~((uint32_t)1<<ch);
		g_pRecSet->StopRecord(ch,RECORD_MANUAL,true);
	}

	return 0;
}

int SET_RECORD_SWITCH(int chSwith)
{
	CRecordSet::MANUAL_SWITCH = chSwith;

	for(int ch = 0; ch < g_pRecSet->GetMaxCHNum() ;ch++)
	{
		if(!(CRecordSet::MANUAL_SWITCH &((int64_t)1<<ch)))
		{
			g_pRecSet->StopRecord(ch,FS_RECORD_MANUAL);
		}
	}

	return 0;
}

void SET_AUDIO_REC_SWITCH(int ch,int bEnable)
{
	g_pRecSet->SetEnableAudio(ch,bEnable);
}

char *  STORAGE_GET_CUR_RECFILE(int ch)
{
	return g_pRecSet->GetRecFile(ch);
}

static int STORAGE_FORMAT_COM(char * dev,int recSizeMB)
{
	int ret = 0;
//	CStorageCommon storageCom;
//	uint32_t fileSizeMB    = 128;
//	uint32_t fileSize      = SIZE_MB(fileSizeMB);
//	uint32_t indexInfoSize = SIZE_4KB;
//	if(recSizeMB >= 64)
//	{
//		fileSizeMB = recSizeMB;
//	}
//
//	ret = storageCom.Init(dev,fileSizeMB,indexInfoSize);
//	if(ret < 0)
//	{
//		fprintf(stderr,"Init file index fail filesize %d dev %s.\n",fileSize,dev);
//		return ret;
//	}
	//预览分配8个文件录像文件,以便于后续文件录像中途不会停顿太久
// 	uint32_t index = 0;
// 	char filePath[60] = {0};
// 	char tmpPath[60] ={0};
// 	char cmd[60] = {0};
//
// 	GetFileDestPath(tmpPath,dev);
// 	if(-1 == access(filePath,0))
// 	{
// 		#ifdef _WIN32
// 			strcat(tmpPath,"Record\\");
// 			CreateDirectory(tmpPath,NULL);
// 		#else
// 			strcat(tmpPath,"Record/");
// 			sprintf(cmd,"mkdir -p %s",tmpPath);
// 			system(cmd);
// 		#endif
// 	}
//
// 	//初始五分钟避免时间太久
// 	uint32_t maxFileNum = storageCom.GetMaxRecordNum();
// 	time_t startTm,curIm,endTm;
// 	time_t totalSecs = 0;
// 	int   failCnt   = 0;
//
//
// 	time(&startTm);
//
// 	for(index = 0; index < maxFileNum;index++)
// 	{
// 		sprintf(filePath,"%s%05d.asf",tmpPath,index);
// 		if(-1 == access(filePath,0))
// 		{
// 			ret = CSerialFileBase::AllocSpace(filePath,fileSize);
// 			if(ret < 0)
// 			{
// 				if(failCnt >= 3)
// 				{
// 					break;
// 				}
// 				TRACE_ERR("Alloc file fail. index %d \n",index);
// 				failCnt ++;
// 			}
// 		}
// 		time(&curIm);
// 		if((curIm + 30) > startTm)
// 		{
// 			TRACE_ERR("Alloc file too loog %d secs skip.\n",curIm - startTm);
// 			break;
// 		}
//
// 	}
//
// 	time(&endTm);
// 	totalSecs = endTm - startTm;
// 	TRACE_ERR("Total AllocSpace time %d s total rec num %d file size %d MB.\n",totalSecs ,maxFileNum,fileSizeMB);

	return ret;
}

int STORAGE_FORMAT_TO_RECDISK(char * dev,int recSizeMB,int comdiskMB)
{
	int ret = 0;
	if(dev == NULL)
	{
		fprintf(stderr,"No device  %s.\n",dev);
		return ERR_NO_DEVICE;
	}
#ifdef _WIN32
	if(strstr(dev,"\\\\.\\PhysicalDrive"))
#else
	if(strstr(dev,"/dev/sd"))
#endif
	{   //裸设备格式化
//		ret = STORAGE_FORMAT_RAW(dev,recSizeMB,comdiskMB);
	}
	else
	{
		ret = STORAGE_FORMAT_COM(dev,recSizeMB);
	}

	return 0;
}

int STORAGE_GET_DATA_PERCENT()
{

	return g_pFileMangerArr.GetDataPercent();
}

void STORAGE_SET_VIDEO_RESSOLUTION(int width, int height,int channel)
{
	if( -1 == channel)
	{
		int i = 0;
		for(i = 0; i < g_storageCfg.channelNum; i++)
		{
			g_pRecSet->SetResolution(width,height,i);
		}
	}
	else
	{
		 g_pRecSet->SetResolution(width,height,channel);
	}

}

int FIFO_READ_FRAME(FIFO_BUF_INFO * fifoInfo,int ch,int clientID)
{

	if( ch >= g_storageCfg.channelNum)
	{
		return ERR_OVER_MAX_CHANNEL;
	}
	int ret =0;

	ret= MML_Read_Frame(fifoInfo->buf,g_storageCfg.getfrm_sz,ch,clientID);

	return ret;
}

int FIFO_GET_FRAME_WATER(int ch,int clientID)
{

	if( ch >= g_storageCfg.channelNum)
	{
		return ERR_OVER_MAX_CHANNEL;
	}
	int ret = 0;


	return ret;

}



int REC_WRITE_GPSINFO(unsigned char * buf,uint32_t dataSize,int ch)
{

	if( ch >= g_storageCfg.channelNum)
	{
		return ERR_OVER_MAX_CHANNEL;
	}

	g_pRecSet->WriteGPSInfo(ch,buf,dataSize);

	return 0;
}



RECORD_CH_INFO GET_RECORD_CH_INFO()
{
	RECORD_CH_INFO chInfo;

	chInfo.sptChNum    = g_storageCfg.channelNum;

	memset(chInfo.recType,0,32);

	for(int ch = 0; ch < g_storageCfg.channelNum; ch++)
	{
		chInfo.recType[ch] = (char)g_pRecSet->GetRecordType(ch);
	}

	return chInfo;
}

int STOP_RECORD()
{
	g_pRecSet->Stop();
	return 0;
}

void SET_REC_CYCLE(int bEnable)
{
	g_storageCfg.bCycleRec = bEnable;
	g_pRecSet->SetRecycleRecord(bEnable);
}

int SET_PREARE_REC(bool bEnable, int nSecs)
{
	g_storageCfg.bPrepare = bEnable;
	g_pRecSet->SetPrepareRec(bEnable,nSecs);
	return 0;
}

///搜索当月中存在录像的天数
int SEARCH_RECORD_ALLDAY(char* recDayBuf,int bufSize,int64_t chBit)
{
	VEC_REC_DAY_T  vecRecDay;

//	g_pFileMangerArr.SearchRecAllDay(vecRecDay);

	char * pBuf = recDayBuf;
	for(int i = 0; i < (int)vecRecDay.size(); i++)
	{
		REC_DAY * pRecDay = (REC_DAY *)pBuf;;

		pRecDay->tm_day_start = vecRecDay[i].tm_day_start;
		pRecDay->tm_day_end   =  vecRecDay[i].tm_day_end;

		pBuf += sizeof(REC_DAY);
	}

	return vecRecDay.size();
}
//
int SEARCH_REC_DAYOFMONTH(int year, int month, int recType)
{
	int64_t tmStart = 0;
	int64_t tmEnd = 0;
	int chNum = g_storageCfg.channelNum;
	vector<int32_t> vecDayBIT(32);
	int dayBIT = 0;
	int ret = GetMonthTime(tmStart, tmEnd, year,month);

//	ret = g_pFileMangerArr.SearchDayOfMonth(tmStart,tmEnd,recType,vecDayBIT);

	if(ret > 0 )
	{
		for(int i = 0 ; i < chNum; i++ )
		{
			if(vecDayBIT[i])
			{
				dayBIT |= vecDayBIT[i];
			}
		}
	}

	return dayBIT;
}

int SEARCH_REC(unsigned char* fileBuf,int bufSize,time_t tmStart, time_t tmEnd, int32_t chBit,int recType,int clientID)
{
	int ret = 0;
	unsigned char* recBuf = fileBuf;
	int  maxFileNum = bufSize /sizeof(RECORD_SEGMENT);
	bool bSameRec = false;
	int  idx = 0;

	TRACE("1 SerchRecord start clientID %d chLst %d recType %d start time %ld end time %ld maxFileNum %d.\n",
		      clientID,chBit,recType,tmStart,tmEnd,maxFileNum);

	PrintTimeSec(tmStart,tmEnd,(char *)"Search Time");

	int64_t tmStartMS = (int64_t)tmStart * 1000;
	int64_t tmEndMS   = (int64_t)tmEnd   * 1000;
	if( NULL == recBuf)
	{
		return ERR_DATA_BUF_EMPYT;
	}

	if(tmStart > tmEnd)
	{
		TRACE("Error search time %ld %ld .\n",tmStart,tmEnd);
		PrintTimeSec(tmStart,tmEnd,NULL);
		return ERR_PARAM;
	}

	if( 0 == chBit )
	{
		TRACE("Channel list is empty.\n");
		return ERR_PARAM;
	}

	//默认搜索全部录像
    if( 0 == recType )
    {
       recType = -1;
    }

	int chNum = 32;
	vector<uint8_t> vecCH(chNum);

	for(size_t i = 0 ; i < vecCH.size(); i++)
	{
		if((chBit)>>i &0x01)
		{
			vecCH[i] = 1;
		}
		else
		{
			vecCH[i] = 0;
		}
	}

	map<int, MAP_CH_FILE_T>::iterator itClientFile	= g_mpClientFile.find(clientID);
	if(itClientFile == g_mpClientFile.end())
	{
		MAP_CH_FILE_T mpChFile;
		g_mpClientFile.insert(map<int, MAP_CH_FILE_T>::value_type(clientID,mpChFile));
		itClientFile = g_mpClientFile.find(clientID);
		TRACE("searchRecord Create new ID %d \n",clientID);
	}

	MAP_CH_FILE_T * pMapPerChFile = &(itClientFile->second);

	pMapPerChFile->clear();

	ret = g_pFileMangerArr.SearchRecord(tmStartMS,tmEndMS,recType,vecCH,maxFileNum,(*pMapPerChFile),true);

	if(ret <= 0)
	{
		return 0;
	}

	pMapPerChFile    = &(itClientFile->second);
	MAP_CH_FILE_T::iterator itChFile;       //f
	REC_FILE_LIST::iterator itRecFile;	//file of channel
	REC_FILE_LIST::iterator itRecFileBak;	//file of channel
	REC_FILE_LIST* pRecFile = NULL;
	unsigned int tmStartSec = 0;
	unsigned int tmEndSec   = 0;
	int info_len =  sizeof(FILE_INFO);
	FILE_INFO * pFile = NULL;
	int ch = 0;
	for(itChFile = pMapPerChFile->begin(); itChFile != pMapPerChFile->end(); itChFile++)
	{
		pRecFile = (REC_FILE_LIST*) &(itChFile->second) ;
		ch       = itChFile->first;
		TRACE("CH%d  ecord list num %d",ch,pRecFile->size());
		for(itRecFile = pRecFile->begin(); itRecFile != pRecFile->end();itRecFile++)
		{
			pFile = (FILE_INFO * )(recBuf + idx * info_len);

			pFile->channel   = ch;
			pFile->diskIndex = itRecFile->diskIndex;
			pFile->recordType = itRecFile->recordType;
			pFile->tmStart   = itRecFile->tmStart;
			pFile->tmEnd     = itRecFile->tmEnd;
			pFile->fileSize = itRecFile->length;
			pFile->status   = itRecFile->status;
			idx++;
		}
	}

	return ret;
}

int SEARCH_REC_BY_PATHTYPE(char* fileBuf,int number, int type ,int path)
{
	int ret = 0;

	typedef struct _FILE_RET_INFO_
	{
		uint16_t	index;     //1 ~ 99999
		uint8_t		path;      //0-/NOR; 1-/EVT; 2-/PHO;
		uint8_t		type;      //0-"NOR_"; 1-"EVT_"; 2-"PHO_"; 3-"_D1_";
		uint8_t		suffix;    //0-".mp4"; 1-".jpg" 2-".avi"
		uint8_t		reserved[3];
		uint32_t	size;      //unit bytes
		uint32_t	date;      //File created time from 1970/1/1-0:0:0 ,unit seconds
	}FILE_RET_INFO;

	char* recBuf = fileBuf;
	int recPos   = 0;
	int  maxFileNum = number;
	bool bSameRec = false;
	int  idx      = 0;
	int  chBit   = -1;
	int  recType = 0;
	int  clientID = 0;

//	PrintTimeSec(tmStart,tmEnd,(char *)"Search Time");
	time_t tmStart = 0;
	time_t tmEnd  = 0;
	time(&tmEnd);       //搜索所有时间段的录像

	int64_t tmStartMS = (int64_t)tmStart * 1000;
	int64_t tmEndMS   = (int64_t)tmEnd   * 1000;
	if( NULL == recBuf)
	{
		return ERR_DATA_BUF_EMPYT;
	}

	if(tmStart > tmEnd)
	{
		TRACE("Error search time %ld %ld .\n",tmStart,tmEnd);
		PrintTimeSec(tmStart,tmEnd,NULL);
		return ERR_PARAM;
	}

	if( 0 == chBit )
	{
		TRACE("Channel list is empty.\n");
		return ERR_PARAM;
	}

	//默认搜索全部录像
	if( 0 == recType )
	{
		recType = -1;
	}

	int chNum = 32;
	vector<uint8_t> vecCH(chNum);

	for(size_t i = 0 ; i < vecCH.size(); i++)
	{
		if((chBit)>>i &0x01)
		{
			vecCH[i] = 1;
		}
		else
		{
			vecCH[i] = 0;
		}
	}

	map<int, MAP_CH_FILE_T>::iterator itClientFile	= g_mpClientFile.find(clientID);
	if(itClientFile == g_mpClientFile.end())
	{
		MAP_CH_FILE_T mpChFile;
		g_mpClientFile.insert(map<int, MAP_CH_FILE_T>::value_type(clientID,mpChFile));
		itClientFile = g_mpClientFile.find(clientID);
		TRACE("searchRecord Create new ID %d \n",clientID);
	}

	MAP_CH_FILE_T * pMapPerChFile = &(itClientFile->second);

	pMapPerChFile->clear();

	ret = g_pFileMangerArr.SearchRecord(tmStartMS,tmEndMS,recType,vecCH,maxFileNum,(*pMapPerChFile),true);

	if(ret <= 0)
	{
		return 0;
	}

	pMapPerChFile    = &(itClientFile->second);
	MAP_CH_FILE_T::iterator itChFile;       //f
	REC_FILE_LIST::iterator itRecFile;	//file of channel
	REC_FILE_LIST::iterator itRecFileBak;	//file of channel
	REC_FILE_LIST* pRecFile = NULL;

	int info_len =  sizeof(FILE_RET_INFO);
	FILE_RET_INFO * pFile = NULL;
	int ch = 0;

	for(itChFile = pMapPerChFile->begin(); itChFile != pMapPerChFile->end(); itChFile++)
	{
		pRecFile = (REC_FILE_LIST*) &(itChFile->second) ;
		ch       = itChFile->first;
		TRACE("CH%d  ecord list num %d",ch,pRecFile->size());
		for(itRecFile = pRecFile->begin(); itRecFile != pRecFile->end();itRecFile++)
		{
			pFile = (FILE_RET_INFO * )(recBuf + idx * info_len);

			pFile->index = idx;
			pFile->size =  itRecFile->length;;
			if(itRecFile->recordType == RECORD_IOALARM)
			{
				pFile->path = 1;
				pFile->type = 1;
			}
			else
			{
				pFile->path = 0;
				pFile->type = 0;
			}

			pFile->suffix = 2;
			pFile->date = (uint32_t)(itRecFile->tmStart );

			idx++;
		}
	}

	return ret;
}

int GET_FILENAME_BYINFO(char * fileName,FILE_INFO finfo)
{
	int ret = 0;
	if(fileName == NULL)
	{
		return  ERR_EMPTY_POINT;
	}

	ret = g_pFileMangerArr.GetFilePath(fileName,finfo);

	return ret;
}

int  SEARCH_HISTORY_REC(unsigned char* fileBuf,int bufSize,time_t tmStart,time_t tmEnd,int32_t ch,int recType,int clientID)
{
	int ret      = 0;
	unsigned char* recBuf = fileBuf;
	int totalNum   = 0;
	int destNum   = 0;

	int  maxFileNum = bufSize /8;
	int  chBit = 1 <<ch;
	bool bSameRec = false;
	int chNum = g_storageCfg.channelNum;
	recType = -1;

	typedef struct _tx_history_video_range
	{
		unsigned int start_time;     //视频片段开始时间 单位s.
		unsigned int end_time;       //视频片段结束时间 单位s.
	} tx_history_video_range;

	maxFileNum = bufSize /sizeof(tx_history_video_range);

	TRACE("SerchRecord start clientID %d chLst %d recType %d start time %ld end time %ld maxFileNum %d.\n",
		clientID,ch,recType,tmStart,tmEnd,maxFileNum);

	PrintTimeSec(tmStart,tmEnd,(char *)"Search Time");

	int64_t tmStartMS = (int64_t)tmStart * 1000;
	int64_t tmEndMS   = (int64_t)tmEnd   * 1000;
	if( NULL == recBuf)
	{
		return ERR_DATA_BUF_EMPYT;
	}

	if(tmStart > tmEnd)
	{
		TRACE("Error search time %ld %ld .\n",tmStart,tmEnd);
		PrintTimeSec(tmStart,tmEnd,NULL);
		return ERR_PARAM;
	}

	if( ch >= chNum )
	{
		TRACE("channel is error");
		return ERR_PARAM;
	}

	//默认搜索全部录像
	if( 0 == recType )
	{
		recType = -1;
	}

	TRACE("SerchRecord end merge num %d totalNum %d .\n",destNum,maxFileNum);

	return destNum;
}

//回放接口,可以支持远程点播,ClientID  0:表示本地用户　　1：远程用户　
int PLAYBACK_BYTIME(time_t startTime,time_t endTime, int channel,int clientID)
{
	int ret = 0;
	int64_t tmStart = (int64_t)startTime * 1000;
	int64_t tmEnd   = (int64_t)endTime * 1000;

	TRACE_ERR("Telnet replay channel %d clientID %d.\n ",channel ,clientID);
	PrintTimeMs(tmStart,tmEnd,"telnet replay time");
	if(channel > g_storageCfg.channelNum)
	{
		return ERR_PARAM;
	}

// 	REC_FILE_LIST  * pFileList = NULL;
// 	map<int, MAP_CH_FILE_T>::iterator itClientFile;
// 	MAP_CH_FILE_T::iterator itChFile;
// 	int ch = channel;
// 	vector<CLIENT_INFO> * pvecCInfo;
// 	pvecCInfo = g_pFileMangerArr->GetVecClient();
//
//
// 	if(tmStart == (*pvecCInfo)[channel].startTime &&
// 		tmEnd  == (*pvecCInfo)[channel].endTime  )
// 	{
// 		itClientFile = g_mpClientFile.find(clientID);
// 		if(itClientFile != g_mpClientFile.end())
// 		{
// 			itChFile = itClientFile->second.find(ch);
// 			TRACE("MAP_CH_FILE_T size %d \n",itClientFile->second.size());
// 			if(itChFile != itClientFile->second.end())
// 			{
// 				pFileList = &(itChFile->second);
// 			}
// 		}
// 	}
//
//
// 	TRACE("CH%02d InitChAndTime ch \n",ch);
//
// 	ret = g_pTelnetReplay->InitChAndTime(clientID,ch,tmStart,tmEnd,pFileList);
// 	if(ret >= 0)
// 	{
// 		g_pTelnetReplay->Start(clientID);
// 	}

// g_replaySync[clientID].Init(g_storageCfg.channelNum,REPLAY_NORMAL,startTime);

	return ret;
}

int TELNET_REPLAY(time_t startTime,time_t endTime, int ch,int clientID)
{
	int ret = 0;
	int64_t tmStart = (int64_t)startTime * 1000;
	int64_t tmEnd   = (int64_t)endTime * 1000;

// 	TRACE_ERR("Telnet replay ch %d clientID %d.\n ", ch, clientID);
// 	PrintTimeMs(tmStart,tmEnd,"telnet replay time");
// 	if(ch > g_storageCfg.channelNum)
// 	{
// 		return ERR_PARAM;
// 	}
//
// 	REC_FILE_LIST  * pFileList = NULL;
// 	map<int, MAP_CH_FILE_T>::iterator itClientFile;
// 	MAP_CH_FILE_T::iterator itChFile;
//
// 	vector<CLIENT_INFO> * pvecCInfo;
// 	pvecCInfo = g_pFileMangerArr->GetVecClient();
//
//
// 	itClientFile = g_mpClientFile.find(clientID);
// 	if(itClientFile != g_mpClientFile.end())
// 	{
// 		itChFile = itClientFile->second.find(ch);
// 		TRACE("MAP_CH_FILE_T size %d \n",itClientFile->second.size());
// 		if(itChFile != itClientFile->second.end())
// 		{
// 			pFileList = &(itChFile->second);
// 		}
// 	}

	TRACE("CH%02d InitChAndTime ch \n",ch);
//	ret = g_pTelnetReplay->InitChAndTime(clientID,ch,tmStart,tmEnd,pFileList);
	if(ret >= 0)
	{
//		g_pTelnetReplay->Start(clientID);
	}

	return ret;
}

int PLAYBACK_BYFILEINO(int file_idx, int clientID)
{
	int ret = 0;
	int64_t tmStart = 0;
	int64_t tmEnd   = 0;

	return ret;
}

typedef struct file_info
{
	int fileLen;
	int timeSec;

}file_info_s;

int PLAYBACK_BYFILENAME(char * fileName,int clientID)
{
	int ret = 0;

	g_replayCtrl[clientID].SetPlayMode(REPLAY_NORMAL,1);

	ret = g_replayer->SetPlayMode(clientID,0,REPLAY_NORMAL,1);

	ret = g_replayer->InitRecFile(fileName,0,clientID);
	TRACE(" PLAYBACK_BYFILENAME %s  clientID %d  ret %d .\n",fileName,clientID,ret);


	return ret;
}

int PLAYBACK_GET_INFO(CUR_PLAYFILE_INFO_S * pInfo,int ch)
{
	int ret = 0;

	ret = g_replayer->GetplayInfo((unsigned char * )pInfo, sizeof(CUR_PLAYFILE_INFO_S));

	return ret;
}

int PLAYBACK_PAUSE(int ch,int clientID)
{
	int ret = 0;

	return ret;
}

int PLAYBACK_RESUME(int ch,int clientID)
{
	int ret = 0;
	return ret;
}

int PLAYBACK_STOP(int ch,int clientID)
{
	int ret = 0;

	ret = g_replayer->Stop(clientID,ch);

	return ret;
}

int  PLAYBACK_STATUS(int ch,time_t playTime,int clientID)
{
	bool bPlaying = g_replayer->IsPlaying();
	if(bPlaying)
	{
		return 0;
	}
	else
	{
		return -1;
	}

}
int PLAYBACK_SEEKTIME(time_t time,int ch,int clientID)
{
	int ret = 0;
	TRACE("PLAYBACK_SEEKTIME time %d  ch %d clientID %d.\n ",(int)time,ch,clientID);
	int64_t seekTime = (int64_t)time * 1000;

	PrintTimeMs(seekTime,0,"PLAYBACK_SEEKTIME");
	ret = g_replayer->SeekTime(clientID,ch,seekTime);

	return ret;
}

int PLAYBACK_SETMODE(PLAYBACK_MODE playMod, int speed,int ch,int clientID)
{
	int ret = 0;

	ret = g_replayer->SetPlayMode(clientID,ch,playMod,speed);

	g_replayCtrl[clientID].SetPlayMode(playMod,speed);

	return ret;
}

//取地址
int REPLAY_FIFO_GET_FRAME_ADDR(FIFO_BUF_INFO * fifoInfo,int ch,int clientID)
{
	int ret = 0;

	return ret;
}



//拷贝一帧数据出来
int REPLAY_FIFO_READ_FRAME(unsigned char * buf,int dataSize,int ch,int clientID)
{
	int ret = 0;

	ret = g_replayer->FifoReadFrame(buf,dataSize,ch,clientID);

	return ret;
}

int REPLAY_SYNC_WAIT( unsigned long long frmTm,int mulCH_sync,int ch,int clientID)
{
	if(clientID >= 5)
	{
		return ERR_OVER_MAXCLIENT;
	}

	int ret = 0;
	if(!mulCH_sync) //是否多通道同步回放
	{
		ret = g_replayCtrl[clientID].NormalWait(frmTm,ch);
	}
	else
	{
		ret = g_replayCtrl[clientID].Wait(frmTm,ch);
	}

	return ret;
}

int  REPLAY_GET_MODE(PLAYBACK_MODE_INFO * pModeInfo)
{
	if(pModeInfo == NULL)
	{
		return ERR_PARAM;
	}

	g_replayCtrl[0].GetPlayMode(pModeInfo->palyMod,pModeInfo->speed);

	return 0;
}

int REPLAY_FIFO_READ_GPSINFO(uint32_t gpsTm,unsigned char * buf,int bufSize,int ch,int clientID)
{
	int ret = 0;

	return ret;
}

int REPLAY_FIFO_CLEAR(int ch,int clientID)
{
	int ret = 0;

	return ret;
}



int FORMAT_DISK_RECORD(int diskNO,int recFileSize)
{
	int ret = 0;

	return ret;
}
#ifdef _SPT_BACKUP_

int  BACKUP_AUDIO_PARM(AUDIO_TYPE audoType,int samplerate,int audioChannel,int PCMBitSize)
{
	int ret = g_rec_backup.InitAACEncodeParm((AUDIO_ENCODE_TYPE)audoType,samplerate,audioChannel,PCMBitSize);

	return ret;
}

int BACKUP_START(unsigned char * reclist,int recNum, int fileFormat,const char * filePath)
{
	int ret = 0;
	int idx = 0;


	RECORD_SEGMENT* recSeg;
	REC_FILE_INFO fileInfo;

	if(NULL == reclist)
	{
		return ERR_DATA_BUF_EMPYT;
	}

	if(0 == recNum)
	{
		return ERR_NO_FILE;
	}

	if( NULL == filePath)
	{
		return ERR_PARAM;
	}

	for(idx = 0 ; idx < recNum; idx++)
	{
		recSeg =(RECORD_SEGMENT*)(reclist+ idx* sizeof(RECORD_SEGMENT));

		fileInfo.channel   = recSeg->channel;
		fileInfo.indexNo   = recSeg->indexNO;
		fileInfo.diskIndex = recSeg->diskIndex;
		fileInfo.length    = (uint32_t)recSeg->fileSize;
		fileInfo.tmStart   = recSeg->tmStart;
		fileInfo.tmStart   *= 1000;

		fileInfo.tmEnd     = recSeg->tmEnd;
		fileInfo.tmEnd    *= 1000;

		fileInfo.timeZone  = recSeg->timeZone;
		fileInfo.status    = recSeg->status;
		fileInfo.recordType= recSeg->recordType;

		g_fileLst.push_back(fileInfo);
	}

	map<int, MAP_CH_FILE_T>::iterator itClientFile	= g_mpClientFile.find(0);


	MAP_CH_FILE_T::iterator itChFile;

	if(itClientFile != g_mpClientFile.end())
	{
		itChFile = itClientFile->second.find(0);
	}
		    //f

	ret = g_rec_backup.Init(filePath,g_fileLst,fileFormat);
	g_rec_backup.Start();
	g_fileLst.clear();

	return ret;
}


int BACKUP_STOP()
{
	int ret = 0;

	g_rec_backup.Stop();

    return ret;
}
#endif // _SPT_BACKUP_
//远程下载
int DOWNLOAD_START(int clientID,DOWNLOAD_RECORD pDownloadParam)
{
	int ret = 0;

	return ret;
}

int DOWNLOAD_STOP(int clientID,int ch)
{
	return 0 ;
}

int SET_STORAGECFG(StorageConfig config)
{
	int ret = 0;

	g_storageCfg.channelNum = config.channelNum;
	g_storageCfg.bPrepare   = config.bPrepare;
	g_storageCfg.bCycleRec  = config.bCycleRec;
	g_storageCfg.sptClientNum = config.sptClientNum;

	return ret;
}

StorageConfig GET_STORAGE_CFG()
{
	return g_storageCfg;
}

StorageSpaceInfo GET_DISK_SPACE_INFO()
{
	StorageSpaceInfo spaceInfo;
	DISK_INFO  * pDiskInfo;

	memset(&spaceInfo,0,sizeof(StorageSpaceInfo));
// 	spaceInfo.diskNum = g_diskInfoSet.GetDiskNum();
//
// 	for(i = 0; i < (int)spaceInfo.diskNum ; i++)
// 	{
// 		pDiskInfo = g_diskInfoSet.GetDiskInfo(i);
// 		spaceInfo.freeSpace += pDiskInfo->dataFreeSpace;
// 		spaceInfo.dataPercent =  100 - (pDiskInfo->dataFreeSpace * 100 / pDiskInfo->dataSpace);
// 	}

	return spaceInfo;
}

int FIFO_GET_DATASIZE(int ch)
{
	int ret = 0; //g_pFrmBufArr[ch].GetFrameSize(0);

	return ret;
}


int  STORAGE_GET_FREC_PERCENTT(int ch)
{
	return g_pRecSet->GetWritePercent(ch);
}

uint32_t  STORAGE_GET_FREC_INDEX(int ch)
{
	return g_pRecSet->GetFileIndex(ch);
}

uint32_t  STORAGE_GET_FREC_SN(int ch)
{
	return g_pRecSet->GetCurRecordSN(ch);
}


int STORAGE_GET_CACHE_WATER(int ch)
{
	return g_pRecSet->GetCacheWater(ch);
}

int SET_SCHEDULE_TIME(int ch, SCHDULE_REC schduleTime)
{
	 g_pRecSet->SetSchedule(ch,schduleTime);
	 return 0 ;
}

void LHN_API SetVideoParm(int ch,int width,int height,int frame_rate)
{
	g_pRecSet->SetVideoParm(ch,width,height,frame_rate);

}

void LHN_API SetAudioParm(int ch,int audio_channels, long rate, int bits, int format)
{
	g_pRecSet->SetAudioParm(ch,audio_channels,rate,bits,format);
}

SCHDULE_REC GET_SCHEDULE_TIME(int ch)
{
	SCHDULE_REC schduleRec;

	g_pRecSet->GetSchedule(ch,&schduleRec);

	return schduleRec;
}

int LOCK_RECORD(RECORD_SEGMENT * recSeg)
{
	REC_FILE_INFO fileInfo;

	fileInfo.channel   = recSeg->channel;
	fileInfo.indexNo   = recSeg->indexNO;
	fileInfo.diskIndex = recSeg->diskIndex;
	fileInfo.length    = (uint32_t)recSeg->fileSize;
	fileInfo.tmStart   = recSeg->tmStart;
	fileInfo.tmStart   *= 1000;

	fileInfo.tmEnd     = recSeg->tmEnd;
	fileInfo.tmEnd    *= 1000;

	fileInfo.timeZone  = recSeg->timeZone;
	fileInfo.status    = recSeg->status;
	fileInfo.recordType= recSeg->recordType;
	fileInfo.segIndex  = recSeg->recSegIndex;
	return g_pFileMangerArr.LockFile(fileInfo);
}

int UNLOCK_RECORD(RECORD_SEGMENT * recSeg)
{
	REC_FILE_INFO fileInfo;

	fileInfo.channel   = recSeg->channel;
	fileInfo.indexNo   = recSeg->indexNO;
	fileInfo.diskIndex = recSeg->diskIndex;
	fileInfo.length    = (uint32_t)recSeg->fileSize;
	fileInfo.tmStart   = recSeg->tmStart;
	fileInfo.tmStart   *= 1000;

	fileInfo.tmEnd     = recSeg->tmEnd;
	fileInfo.tmEnd    *= 1000;

	fileInfo.timeZone  = recSeg->timeZone;
	fileInfo.status    = recSeg->status;
	fileInfo.recordType= recSeg->recordType;
	fileInfo.segIndex  = recSeg->recSegIndex;

	return g_pFileMangerArr.UnlockFile(fileInfo);
}


int  ExportRecordFile(char * dev,int fileIdx,int fileSize,char * destFile)
{
	int ret = 0;

// 	CSerialFileRaw rawFile;
// 	CSerialFileCom comfile;
// 	TRACE("dev %s fileIndex %d fileSize %d MB destFile.\n",
// 		   dev,fileIdx,fileSize>>20,destFile);
//
// 	uint64_t fileLBA = g_diskInfoSet.GetAssignFileLBA(dev,fileIdx);
//
// 	CSCSI_Dev* pDev = g_scsiDevFac.CreateScsiDev(dev);
//     if( NULL == pDev)
//     {
//         TRACE_ERR("No device %s .\n", dev);
//         return ERR_NO_DEVICE;
//     }
// 	ret = rawFile.Open((void*)pDev,fileLBA,fileSize,SCSI_RDWR);
// 	if(ret < 0)
// 	{
// 		TRACE_ERR("Open rawFile dev %s %d fail. ret %d .\n",dev,fileIdx,ret);
// 		return ret;
// 	}
//
// 	ret = comfile.Open(destFile,0,fileSize,SCSI_RDWR);
// 	if(ret < 0)
// 	{
// 		TRACE_ERR("Open destfile %s fail. ret %d .\n",destFile,ret);
// 		return ret;
// 	}
//
// 	ret = CSerialFileBase::CopyFile(&rawFile,&comfile,512<<10);
// 	TRACE("ExportRecordFile end .ret %d \n",ret );

	return ret;
}


int MML_FIFO_Open(int ch, int buf_sz)
{
	int ret = 0;

	return ret;
}

int MML_Write_frame(unsigned char * buf,uint32_t dataSize,int frameType,int ch,int64_t pts)
{
	int ret = 0;

	if(ch > g_storageCfg.cache_chNum)
	{
		return ERR_OVER_MAX_CHANNEL;
	}

	CLHNFrame *pFIFO = & g_pFrmBufArr[ch];

	ret = pFIFO->WriteFrame(buf,dataSize,frameType,pts);

	return ret;
}

int MML_Write_IFame_sps(unsigned char * buf,uint32_t dataSize,unsigned char * sps_pps_buf,int sps_pps_sz,int ch,int64_t pts)
{
	int ret = 0;

	if(ch > g_storageCfg.cache_chNum)
	{
		return ERR_OVER_MAX_CHANNEL;
	}

	CLHNFrame *pFIFO = & g_pFrmBufArr[ch];

	ret = pFIFO->WriteIFrame(buf,dataSize,sps_pps_buf,sps_pps_sz,pts);

	return ret;
}


int MML_Read_Frame(unsigned char * buf, int buf_sz,int ch,int clientID)
{
	int ret = 0;

	if(ch > g_storageCfg.cache_chNum)
	{
		return ERR_OVER_MAX_CHANNEL;
	}

#ifdef _SIMULATE_RECORD_

	if(g_mulData->IsSimuData())
	{
		if(!g_mulData->IsOpened())
		{
			//	TRACE_ERR("Test data is not open.\n");
			return ERR_FILE_NOOPEN;
		}

		if(g_mulData->IsFrameLost())
		{
			return ERR_DATA_SIZE;;
		}
		ret = g_mulData->FIFO_GET_FRAME( buf,buf_sz,ch,0);

		return ret;
	}

#endif
	CLHNFrame *pFIFO = & g_pFrmBufArr[ch];

	if(pFIFO->IsOpen())
	{
		ret = pFIFO->ReadFrame(buf,buf_sz,clientID);	
	}
	return ret;
}

int MML_FIFO_SeekTime(int64_t startTime,int prepareSecs,int ch)
{
	int ret = 0;
	if(ch > g_storageCfg.cache_chNum)
	{
		return ERR_OVER_MAX_CHANNEL;
	}

	CLHNFrame *pFIFO = & g_pFrmBufArr[ch];
	return  pFIFO->SeekTime(startTime,prepareSecs);
}

int MML_FIFO_Refresh(int ch ,int clientID)
{
	int ret = 0;
	if(ch > g_storageCfg.cache_chNum)
	{
		return ERR_OVER_MAX_CHANNEL;
	}

	CLHNFrame *pFIFO = & g_pFrmBufArr[ch];
	return  pFIFO->SeekNewleastFrm(clientID);
}

int MML_FIFO_Water(int ch,int clientID)
{
	if(ch > g_storageCfg.cache_chNum)
	{
		return ERR_OVER_MAX_CHANNEL;
	}

	CLHNFrame *pFIFO = & g_pFrmBufArr[ch];
	return  pFIFO->GetDataWater(clientID);
}

int  MML_FIFO_DataSize(int ch,int clientID)
{

	if(ch > g_storageCfg.cache_chNum)
	{
		return ERR_OVER_MAX_CHANNEL;
	}

	CLHNFrame *pFIFO = & g_pFrmBufArr[ch];
	return  pFIFO->GetDataSize(clientID);
}

int MML_FIFO_Free(int ch,int clientID)
{

	if(ch > g_storageCfg.cache_chNum)
	{
		return ERR_OVER_MAX_CHANNEL;
	}

	CLHNFrame *pFIFO = & g_pFrmBufArr[ch];
	return  pFIFO->FreeFrameSpace(clientID);
}

int  MML_FIFO_BitRateByte(int ch)
{
	if(ch > g_storageCfg.cache_chNum)
	{
		return ERR_OVER_MAX_CHANNEL;
	}

	CLHNFrame *pFIFO = & g_pFrmBufArr[ch];
	return  pFIFO->GetBitRate();
}


int REPLAY_TEST(int ch)
{
	int ret = 0;

	TRACE("Start Test replay.\n");

	ret = g_replayer->StartTestReplay();

	return ret;
}

int  REPLAY_TEST_STOP(int ch)
{
	int ret = 0;

	ret = g_replayer->StopTestReplay();

	return ret;
}

int GET_RECORD_INDEX_INFO(uchar_t * buf,int buf_size,int ch)
{
	CRecWriteBase * pWriter = g_pRecSet->GetRecWriter(ch);

	if( NULL == pWriter)
	{
		return -1;
	}
	int idx_num = 0;

	idx_num = pWriter->ReadIndexInfo(buf,buf_size);

	return idx_num;
}

int  GET_RECORD_GPS_INFO(unsigned char  * buf,int buf_size,int ch)
{
	CRecWriteBase * pWriter = g_pRecSet->GetRecWriter(ch);

	if( NULL == pWriter)
	{
		return -1;
	}
	int idx_num = 0;

	idx_num = pWriter->ReadGPSInfo(buf,buf_size);

	return idx_num;
};


#include "MultiCHData.h"
int OPEN_SIMULATE(char * file,int chNum)
{
	int ret = 0;
#ifdef _SIMULATE_RECORD_
	ret = g_mulData->Open(file,chNum);
	ret = g_mulData->OpenSimulate();
#endif
	return ret;
}
int GET_SIMULATE_Rate()
{
    #ifdef _SIMULATE_RECORD_
	return g_mulData->GetFrameRate();
	#else
	return 0;
	#endif
}
